JavaScript 是採用語法作用域,也叫做靜態作用域,意思是在語法解析的時候就已經確定作用域。相對地,動態作用域是在函式調用的時候才會決定它的作用域,但此處以 JavaScript 為主,先不多介紹動態作用域。
先撰寫一個簡單的函式來做範例:
function callName() {
let Jack = "傑克";
console.log(Jack); //傑克
}
callName();
上面的函式裡面我們在定義變數後方直接使用 console.log
試著把 Jack
印出來,在執行函式後就會執行該段程式碼,並把值給印出來得到 傑克
接下來讓我們把裡面的 console.log
拿到外面來試著印印看:
function callName() {
let Jack = "傑克";
}
callName();
console.log(Jack); // Jack is not defined
此時會得到 Jack is not defined
並沒有被定義的結果
為什麼呢?
原因是因為 JavaScript 的作用域是在這個函式裡面,所以當我們在函式裡面宣告一個變數的時候,外層是讀不到該變數的。
JavaScript 的作用域是一層一層向內的,外層會有一個全域的作用域,內層則是被 function
所包著
以下圖為例,這裡有兩個不同的函式,這兩個函式的作用域就是獨立的,而在外層還有一個全域的作用域包著這兩個函式。
如果在某個作用域內需要特定變數,但在該作用域內沒有該變數的時候,就會向外查找,意思是往外面的作用域去找有沒有該變數可以使用,如果外面有該變數可以使用就會直接拿來使用。但如果外面也找不到該變數的話,就會顯示變數沒有被定義的錯誤。
此處再以一段程式碼為例:
let value = 1;
function fn1(){
console.log(value); // 語法(靜態)作用域:1
// 動態作用域:2
}
function fn2(){
let value = 2;
fn1();
}
fn2();
雖然在第二個函式內部重新賦予了 value
的值,但因為作用域如同前面所說,靜態作用域在語法解析的時候就已經確定作用域,所以我們在寫 function
的時候,作用域就已經確定了,並不會在執行過程中再次改變作用域。
所以在 fn1
執行時不會受到 fn2
的影響,且在內部找不到 value
這個變數,於是就會向外查找並印出該值。
如果是動態作用域的語法,則會在調用該函式時才會決定作用域,所以此處 fn1
執行時會向外查找到 fn2
內的變數 value
並印出該值。
參考資料
線上課程